// Package scanner Nginx 配置扫描器
package scanner

import (
	"bufio"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"
)

// NginxScanner Nginx 配置扫描器
type NginxScanner struct {
    configDirs []string // Nginx 配置目录列表
}

// NewNginxScanner 创建 Nginx 扫描器
func NewNginxScanner() *NginxScanner {
	// 常见的 Nginx 配置目录
	configDirs := []string{
		"/etc/nginx/sites-enabled",
		"/etc/nginx/conf.d",
		"/usr/local/nginx/conf/vhosts",
		"/opt/nginx/conf/vhosts",
	}

    return &NginxScanner{configDirs: configDirs}
}

// NewNginxScannerWithDirs 以自定义目录创建扫描器
// 允许通过 CLI/配置覆盖默认扫描目录，提升适配性
func NewNginxScannerWithDirs(dirs []string) *NginxScanner {
    if len(dirs) == 0 {
        return NewNginxScanner()
    }
    return &NginxScanner{configDirs: dirs}
}

// Scan 扫描 Nginx 配置
func (s *NginxScanner) Scan() ([]*SiteInfo, error) {
	var sites []*SiteInfo

	// 遍历所有配置目录
	for _, dir := range s.configDirs {
		// 检查目录是否存在
		if _, err := os.Stat(dir); os.IsNotExist(err) {
			continue
		}

		// 读取目录中的所有配置文件
		entries, err := os.ReadDir(dir)
		if err != nil {
			continue
		}

		for _, entry := range entries {
			if entry.IsDir() {
				continue
			}

			// 只处理 .conf 文件
			if !strings.HasSuffix(entry.Name(), ".conf") {
				continue
			}

			configPath := filepath.Join(dir, entry.Name())

			// 解析配置文件
			siteInfo, err := s.parseConfigFile(configPath)
			if err != nil {
				// 跳过解析失败的文件
				continue
			}

			if siteInfo != nil {
				sites = append(sites, siteInfo)
			}
		}
	}

	return sites, nil
}

// parseConfigFile 解析 Nginx 配置文件
func (s *NginxScanner) parseConfigFile(configPath string) (*SiteInfo, error) {
	file, err := os.Open(configPath)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var (
		domains  []string
		certPath string
		keyPath  string
		inServer bool
		hasSSL   bool
	)

	// 正则表达式
	serverNameRe := regexp.MustCompile(`^\s*server_name\s+(.+);`)
	sslCertRe := regexp.MustCompile(`^\s*ssl_certificate\s+(.+);`)
	sslKeyRe := regexp.MustCompile(`^\s*ssl_certificate_key\s+(.+);`)
	listenSSLRe := regexp.MustCompile(`^\s*listen\s+.*\bssl\b`)

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text()

		// 检测 server 块
		if strings.Contains(line, "server {") {
			inServer = true
			continue
		}

		if !inServer {
			continue
		}

		// 检测 server 块结束
		if strings.TrimSpace(line) == "}" {
			break
		}

		// 检测 SSL 监听
		if listenSSLRe.MatchString(line) {
			hasSSL = true
		}

		// 提取 server_name
		if matches := serverNameRe.FindStringSubmatch(line); matches != nil {
			domainStr := strings.TrimSpace(matches[1])
			// 分割多个域名
			for _, domain := range strings.Fields(domainStr) {
				// 过滤掉特殊值
				if domain != "_" && domain != "localhost" {
					domains = append(domains, domain)
				}
			}
		}

		// 提取证书路径
		if matches := sslCertRe.FindStringSubmatch(line); matches != nil {
			certPath = strings.TrimSpace(matches[1])
		}

		// 提取私钥路径
		if matches := sslKeyRe.FindStringSubmatch(line); matches != nil {
			keyPath = strings.TrimSpace(matches[1])
		}
	}

	// 只处理 SSL 站点
	if !hasSSL || len(domains) == 0 || certPath == "" || keyPath == "" {
		return nil, nil
	}

	// 使用第一个域名作为站点名称
	siteName := domains[0]

	// 尝试读取证书信息
	var expiry time.Time
	var serial string
	var subject string

	if _, err := os.Stat(certPath); err == nil {
		expiry, serial, subject, _ = parseCertificate(certPath)
	}

	return &SiteInfo{
		Name:          siteName,
		Domains:       domains,
		ConfigFile:    configPath,
		CertPath:      certPath,
		KeyPath:       keyPath,
		CurrentExpiry: expiry,
		CertSerial:    serial,
		CertSubject:   subject,
	}, nil
}
